/*
 * UserGuard.java
 *
 * Created on July 1, 2007, 4:24 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.app.auth;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.atomojo.app.App;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.Cookie;
import org.restlet.security.ChallengeAuthenticator;
import org.restlet.security.Verifier;

/**
 *
 * @author alex
 */
public class UserGuard extends ChallengeAuthenticator
{
   
   ChallengeScheme myScheme;
   AuthService authService;
   List<String> requiredGroups;
   
   /** Creates a new instance of UserGuard */
   public UserGuard(Context context,ChallengeScheme scheme,String realm,AuthService authService)
   {
      super(context,scheme,realm);
      this.requiredGroups = new ArrayList<String>();
      this.authService = authService;
      setVerifier(new Verifier() {
         public int verify(Request request, Response response) {
            request.getAttributes().put(App.AUTH_SERVICE_ATTR,UserGuard.this.authService);
            ChallengeResponse cr = request.getChallengeResponse();
            Cookie cookie = request.getCookies().getFirst("I");

            // We must have one of these to check
            if (cr==null && cookie==null) {
               return Verifier.RESULT_MISSING;
            }

            // If we have new credentials, check them first
            if (cr!=null) {
               String identifier = request.getChallengeResponse()
                      .getIdentifier();
               char[] secret = request.getChallengeResponse().getSecret();

               // Check the credentials
               if ((identifier != null) && (secret != null)) {
                  if (getLogger().isLoggable(Level.FINE)) {
                     getLogger().fine("Authenticating " + identifier);
                  }
                  try {
                     User user = UserGuard.this.authService.authenticate(identifier, new String(secret));
                     if (user != null) {
                        if (getLogger().isLoggable(Level.FINE)) {
                           getLogger().fine("Authenticated: " + user.getAlias() + ", checking groups");
                        }
                     }
                     user = checkUser(request, user);
                     if (user!=null) {
                        return Verifier.RESULT_VALID;
                     }
                  } catch (AuthException ex) {
                     getContext().getLogger().log(Level.SEVERE, "Cannot check authentication.", ex);
                  }
               }
            }

            // Check the identity cookie
            if (cookie != null) {
               try {
                  User user = UserGuard.this.authService.verifySession(cookie.getValue());
                  if (user != null) {
                     if (getLogger().isLoggable(Level.FINE)) {
                        getLogger().fine("Valid session for: " + user.getAlias() + ", checking groups");
                     }
                  }
                  user = checkUser(request, user);
                  if (user!=null) {
                     return Verifier.RESULT_VALID;
                  }
               } catch (AuthException ex) {
                  getContext().getLogger().log(Level.SEVERE, "Cannot check authentication.", ex);
               }
            }

            return Verifier.RESULT_INVALID;
         }
      });
   }
   
   public List<String> getRequiredGroups() {
      return requiredGroups;
   }
   
   User checkUser(Request request,User user) {
       if (user!=null && !requiredGroups.isEmpty()) {
          for (String name : requiredGroups) {
             if (!user.getGroups().contains(name)) {
                return null;
             }
          }
       }
       if (user!=null) {
          if (getLogger().isLoggable(Level.FINE)) {
             getLogger().fine("Accepted: "+user.getAlias());
          }
       }
       if (user!=null) {
          request.getAttributes().put(App.USER_ATTR,user);
       }
       return user;
    }
    
}
